package com.douqu.game.battle.entity.aobject;

import com.douqu.game.battle.controller.sprite.MonsterController;
import com.douqu.game.battle.controller.sprite.PlayerController;
import com.douqu.game.battle.controller.sprite.SpriteController;
import com.douqu.game.battle.entity.BattleSkill;
import com.douqu.game.battle.route.RouteObject;
import com.douqu.game.battle.server.GameServer;
import com.douqu.game.battle.util.BattleUtils;
import com.douqu.game.battle.util.MsgUtils;
import com.douqu.game.core.config.battle.SkillConfig;
import com.douqu.game.core.config.card.CardConfig;
import com.douqu.game.core.config.challenge.BattleInitConfig;
import com.douqu.game.core.config.challenge.CardParamConfig;
import com.douqu.game.core.config.challenge.WorldBossConfig;
import com.douqu.game.core.config.common.Position;
import com.douqu.game.core.config.sprite.SoldierConfig;
import com.douqu.game.core.e.E_Attribute;
import com.douqu.game.core.e.E_BattleAObjectStatus;
import com.douqu.game.core.e.E_PlayerStatus;
import com.douqu.game.core.entity.Player;
import com.douqu.game.core.entity.battle.SpriteTemp;
import com.douqu.game.core.entity.db.CardDB;
import com.douqu.game.core.factory.ConstantFactory;
import com.douqu.game.core.factory.DataFactory;
import com.douqu.game.core.protobuf.SGCommonProto;
import com.douqu.game.core.util.LogUtils;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Created by bean on 2017/7/25.
 */
public class BattleSoldierAObject extends BattleAObject {


    /**
     * 路线列表
     */
    private List<Position> routeList;

    /**
     * 当前走到哪一步
     */
    private int curRouteIndex;

    /**
     * 出生时间
     */
    private long bornTime;

    /**
     * 召唤出来的兵的主人
     */
    private BattleAObject summonMaster;


    /**
     *
     * @param masterController
     * @param cardDB
     * @param uniqueId
     * @param teamNo
     * @param position
     * @param historySoldierTemp
     * @param bornSoldierCount　这张卡会生成多少个士兵
     */
    public BattleSoldierAObject(SpriteController masterController, CardDB cardDB, int uniqueId, int teamNo, Position position, SpriteTemp historySoldierTemp, int bornSoldierCount)
    {
        super(masterController, cardDB.getConfig().getSoldier(), uniqueId, teamNo, position);

        boolean isInvincible = false;
        if(masterController instanceof PlayerController)
        {
            Player player = ((PlayerController) masterController).getPlayer();
            isInvincible = player.invincible;
        }
        if(isInvincible)
        {
            this.lv = 999999;
            this.star = 10;
            this.fc = 99999999;
            this.hp = maxHp = cacheMaxHp = 99999999;

            this.atk = new BattleAtt(99999999, 0);
            this.def = new BattleAtt(99999999, 0);
            this.cri = new BattleAtt(9999, 0);
            this.rec = new BattleAtt(9999, 0);
            this.add = new BattleAtt(9999, 0);
            this.exd = new BattleAtt(9999, 0);
            this.hit = new BattleAtt(9999, 0);
            this.eva = new BattleAtt(9999, 0);
            this.power   = new BattleAtt(999999, 0);
            this.agility = new BattleAtt(999999, 0);
            this.wisdom  = new BattleAtt(999999, 0);
            this.phyRes  = new BattleAtt(999999, 0);
            this.punRes  = new BattleAtt(999999, 0);
            this.magRes  = new BattleAtt(999999, 0);
        }
        else
        {
            this.lv = cardDB.getLv();
            this.star = cardDB.star;
            if(historySoldierTemp != null)
            {
                int count = bornSoldierCount < 1 ? 1 : bornSoldierCount;
                this.hp = cacheMaxHp = historySoldierTemp.getHp() / count;
                this.hp = hp < 1 ? 1 : hp;
                this.maxHp = historySoldierTemp.getMaxHp() / count;
            }
            else
            {
                long baseValue = cardDB.getAttribute(E_Attribute.HP.getCode());
//                if(cardDB.getSupportParamId() != 0)
//                {
//                    CardParamConfig cardParamConfig = DataFactory.getInstance().getGameObject(DataFactory.CARD_PARAM_KEY, cardDB.getSupportParamId());
//                    if(cardParamConfig != null)
//                    {
//                        baseValue += cardParamConfig.getExtAtt(E_Attribute.HP.getCode());
//                    }
//                }
                this.hp = maxHp = cacheMaxHp = baseValue;
            }

            this.fc = cardDB.fc;
            this.atk = createBattleAtt(cardDB, E_Attribute.ATK);
            this.def = createBattleAtt(cardDB, E_Attribute.DEF);
            this.cri = createBattleAtt(cardDB, E_Attribute.CRI);
            this.rec = createBattleAtt(cardDB, E_Attribute.REC);
            this.add = createBattleAtt(cardDB, E_Attribute.ADD);
            this.exd = createBattleAtt(cardDB, E_Attribute.EXD);
            this.hit = createBattleAtt(cardDB, E_Attribute.HIT);
            this.eva = createBattleAtt(cardDB, E_Attribute.EVA);
            this.power   = new BattleAtt(0, 0);
            this.phyRes  = new BattleAtt(0, 0);
            this.agility = new BattleAtt(0, 0);
            this.punRes  = new BattleAtt(0, 0);
            this.wisdom  = new BattleAtt(0, 0);
            this.magRes  = new BattleAtt(0, 0);
        }

        CardConfig cardConfig = cardDB.getConfig();
        this.moveSpeed = new BattleAtt(cardConfig.getSoldier().moveSpeed, E_Attribute.MOVE_SPEED.getMin());
        this.isMove = true;

        this.defaultSkill = new BattleSkill(masterController, this, cardConfig.getSoldier().getDefaultSkill(cardDB.star));
        this.attackSpeed = new BattleAtt(defaultSkill.getSkillConfig().cdTime, E_Attribute.ATTACK_SPEED.getMin());

        if(BattleUtils.TEST_BATTLE)
        {
            if(teamNo == ConstantFactory.BATTLE_TEAM_1)
            {
                skills = new BattleSkill[BattleUtils.TEAM1_SKILLS.length];
                for(int i = 0; i < skills.length; i++)
                {
                    skills[i] = new BattleSkill(masterController, this, DataFactory.getInstance().getGameObject(DataFactory.SKILL_KEY, BattleUtils.TEAM1_SKILLS[i]));
                }
            }
            else
            {
                skills = new BattleSkill[BattleUtils.TEAM2_SKILLS.length];
                for(int i = 0; i < skills.length; i++)
                {
                    skills[i] = new BattleSkill(masterController, this, DataFactory.getInstance().getGameObject(DataFactory.SKILL_KEY, BattleUtils.TEAM2_SKILLS[i]));
                }
            }
        }
        else
        {
            SkillConfig[] skillConfigs = cardConfig.getSkills(cardDB.star);
            this.skills = new BattleSkill[skillConfigs==null?0:skillConfigs.length];
            for(int i = 0; i < skills.length; i++)
            {
                skills[i] = new BattleSkill(masterController, this, skillConfigs[i]);
            }
        }

        bornTime = DataFactory.currentTime;
        isInitObject = true;

        spriteTemp = new SpriteTemp(cardDB.id, cardDB.getLv(), hp, maxHp, cacheMaxHp, historySoldierTemp==null?cardDB.getIndex():historySoldierTemp.getIndex());

        LogUtils.info("士兵初始化 -> " + detailInfo());
    }

    /**
     * 召唤出来的兵
     * @param masterController
     * @param soldierConfig
     * @param uniqueId
     * @param teamNo
     * @param position
     */
    public BattleSoldierAObject(SpriteController masterController, BattleAObject summonMaster, SoldierConfig soldierConfig, int uniqueId, int teamNo, Position position, float hpRatio, float defRatio, float atkRatio)
    {
        super(masterController, soldierConfig, uniqueId, teamNo, position);

        this.summonMaster = summonMaster;

        this.hp = maxHp = (int) (summonMaster.getMaxHp() * hpRatio);

        this.atk = new BattleAtt((int) (summonMaster.getBaseAtt(E_Attribute.ATK.getCode()) * atkRatio), E_Attribute.ATK.getMin());
        this.def = new BattleAtt((int) (summonMaster.getBaseAtt(E_Attribute.DEF.getCode()) * defRatio), E_Attribute.DEF.getMin());
        this.cri = new BattleAtt(summonMaster.getBaseAtt(E_Attribute.DEF.getCode()), E_Attribute.CRI.getMin());
        this.rec = new BattleAtt(summonMaster.getBaseAtt(E_Attribute.REC.getCode()), E_Attribute.REC.getMin());
        this.add = new BattleAtt(summonMaster.getBaseAtt(E_Attribute.ADD.getCode()), E_Attribute.ADD.getMin());
        this.exd = new BattleAtt(summonMaster.getBaseAtt(E_Attribute.EXD.getCode()), E_Attribute.EXD.getMin());
        this.hit = new BattleAtt(summonMaster.getBaseAtt(E_Attribute.HIT.getCode()), E_Attribute.HIT.getMin());
        this.eva = new BattleAtt(summonMaster.getBaseAtt(E_Attribute.EVA.getCode()), E_Attribute.EVA.getMin());
        this.power   = new BattleAtt(0, 0);
        this.phyRes  = new BattleAtt(0, 0);
        this.agility = new BattleAtt(0, 0);
        this.punRes  = new BattleAtt(0, 0);
        this.wisdom  = new BattleAtt(0, 0);
        this.magRes  = new BattleAtt(0, 0);

        this.moveSpeed = new BattleAtt(soldierConfig.moveSpeed, E_Attribute.MOVE_SPEED.getMin());
        this.isMove = true;

        this.defaultSkill = new BattleSkill(masterController, this, soldierConfig.getDefaultSkill(0));
        this.attackSpeed = new BattleAtt(defaultSkill.getSkillConfig().cdTime, E_Attribute.ATTACK_SPEED.getMin());
        SkillConfig[] skillConfigs = soldierConfig.getStarSkills(summonMaster.star);
        this.skills = new BattleSkill[skillConfigs==null?0:skillConfigs.length];
        for(int i = 0; i < skills.length; i++)
        {
            skills[i] = new BattleSkill(masterController, this, skillConfigs[i]);
        }


        bornTime = DataFactory.currentTime;
        isInitObject = false;

//        spriteTemp = new SpriteSoldierTemp(null, hp, maxHp);

        LogUtils.info("召唤出来的士兵初始化 -> " + detailInfo());
    }

    private BattleAtt createBattleAtt(CardDB cardDB, E_Attribute att)
    {
        float rate = 1;
        if(masterController instanceof MonsterController)
        {
            if(battleController.getBattleType() == SGCommonProto.E_BATTLE_TYPE.BATTLE_TYPE_WORLD_BOSS)
            {
                BattleInitConfig battleInitConfig = ((MonsterController) masterController).getBattleInitConfig();
                WorldBossConfig bossConfig = (WorldBossConfig) battleInitConfig;
                if(bossConfig != null)
                {
                    rate = bossConfig.getExtRate(att);
                }
            }
        }

        long baseValue = cardDB.getAttribute(att.getCode());
//        if(cardDB.getSupportParamId() != 0)
//        {
//            CardParamConfig cardParamConfig = DataFactory.getInstance().getGameObject(DataFactory.CARD_PARAM_KEY, cardDB.getSupportParamId());
//            if(cardParamConfig != null)
//            {
//                baseValue += cardParamConfig.getExtAtt(att.getCode());
//            }
//        }

        return new BattleAtt((long)(baseValue * rate), att.getMin());
    }



    /**
     * 是否可以开始行走了(暂时处理成出生后500毫秒之后)
     * @return
     */
    public boolean isCanStartMove()
    {
        return DataFactory.currentTime - bornTime >= 500;
    }



    public void initRoute(List<Position> list)
    {
        battleController.leaveAstarMap(this);

        this.routeList = list;
        curRouteIndex = 0;
        setPosition(routeList.get(0));
        this.status = E_BattleAObjectStatus.GOING;
    }

//    @Override
//    public boolean isRestrict(BattleAObject target)
//    {
//        if(target instanceof BattleSoldierAObject)
//            return getSoldier().isRestrict(((BattleSoldierAObject) target).getSoldier());
//
//        return false;
//    }


    @Override
    public long addHP(long value)
    {
        long result = super.addHP(value);
        if(result == 0)
            return result;

        if(isDie())
        {
            checkTypeSkill(ConstantFactory.SKILL_TYPE_DIE);

            battleController.removeSoldier(this);
        }

        return result;
    }

    /**
     * 前进
     */
    @Override
    public void go()
    {
        if(!isCanGo())
        {
            //冰冻或者眩晕了，不能行走
            LogUtils.debug("被冰冻或者眩晕了，不能行走 -> " + this);
            return;
        }

        if(status == E_BattleAObjectStatus.BATTLING)
        {
            LogUtils.debug("在战斗中,不能行走了 -> " + this);
            stopMove();
            return;
        }

        if(routeList == null)
        {
            LogUtils.debug("routeList is null, this:" + this);
            stopMove();
            return;
        }

        if(curRouteIndex >= routeList.size()-1)
        {
            LogUtils.debug("走到最后一个点了,this:" + this);
            stopMove();
            return;
        }

        battleController.leaveAstarMap(this);

        if(checkTriggerToAttack())//触发冲锋
        {
            LogUtils.debug("触发冲锋 -> " + this);
            isTriggerToAttack = true;
            MsgUtils.sendPosition("触发冲锋", battleController, this);
            stopMove();
            return;
        }

        if(goTarget != null && goTargetOriginalPosMap.get(goTarget.getUniqueId()) != null)
        {
            if(!goTarget.position.isSame(goTargetOriginalPosMap.get(goTarget.getUniqueId())))
            {
                LogUtils.debug(this + " 前进的目标已经不在原来的位置上:goTarget:" + goTarget + " rote:" + routeList.get(routeList.size() - 1));
                MsgUtils.sendPosition("目标位置变化", battleController, this);
                stopMove();
                return;
            }
        }

        Position goPosition = routeList.get(curRouteIndex+1);

        if(battleController.getAstar().getAstarMap().isObstacleToApplication(goPosition.x, goPosition.y))
        {
            LogUtils.debug("前进的路线是障碍物,重新寻路, this:" + this + " goPosition:" + goPosition);
            MsgUtils.sendPosition("前方障碍", battleController, this);
            stopMove();
            return;
        }

        setPosition(goPosition);

        curRouteIndex++;

//        LogUtils.debug("Time:" + DataFactory.currentTime + " battleId:" + battleController.getId() + " go go go teamNo:" + teamNo + " uniqueId:" + getUniqueId() + " soldierId:" + sprite.getId() + " name:" + sprite.getName() + " position:" + position + "  总的路线:" + routeList.size() + "  最后的点:" + routeList.get(routeList.size() - 1));

        MsgUtils.sendPosition("定时同步", battleController, this);
    }

    /**
     * 停止移动
     */
    @Override
    public void stopMove()
    {
        clearGoTarget();
        curRouteIndex = 0;
        routeList = null;
        status = E_BattleAObjectStatus.FREE;
    }

    @Override
    public boolean checkCanAtk(BattleAObject target)
    {
        if(target == null)
             return false;

        if(!defaultSkill.checkUnitType(target))
            return false;

        return BattleUtils.isInAtkRange(this, target, defaultSkill.getSkillConfig());
    }




    @Override
    public boolean checkDefaultSkillTarget(long currentTime)
    {
        if(isDie())
        {
            LogUtils.debug("已经死了 -> " + this);
            return false;
        }

        if(!isCanAtk())
        {
            //被眩晕了，不能发动攻击
            LogUtils.debug("被眩晕了，不能发动攻击 -> " + uniqueId + " name:" + sprite.name);
            return false;
        }

        if(checkTypeSkill(ConstantFactory.SKILL_TYPE_CD))
        {
            LogUtils.debug("有其它技能要释放:" + uniqueId + " name:" + sprite.name);
            return false;
        }

        //普通攻击速度有可能会受BUFF影响变化
        if(!defaultSkill.isCanRelease(attackSpeed.getAtt()))
        {
            LogUtils.debug("CD时间没到:" + uniqueId + " name:" + sprite.name + " attackSpeed:" + attackSpeed);
            return false;
        }

        if(defaultSkill.getSkillConfig().crystal > masterController.getAttachment().getCurCrystal())
        {
            LogUtils.debug("水晶不够:" + uniqueId + " name:" + sprite.name);
            return false;
        }

        checkDefaultAtk();

        if(defaultSkill.getDefaultAtkTarget() == null)
        {
            BattleAObject defaultTarget = getDefaultSkillTarget();
            if(defaultTarget == null)
                return false;

            LogUtils.debug(this + " 开始攻击 -> 目标:" + defaultTarget + "  攻击距离 -> " + defaultSkill.getSkillConfig().atkRange);
            defaultAtk(defaultTarget);
            return true;
        }
        else
        {
            if(defaultSkill.getDefaultAtkTarget() instanceof BattleMasterAObject)
            {
//                LogUtils.debug("当前攻击目标是主将----------------------------------------->" + this);
                List<BattleAObject> tempList = new CopyOnWriteArrayList<>();
                tempList.addAll(masterController.getAttachment().getTargetBattleTmp().getSoldierList());

                if(tempList.size() > 0)
                {
                    //按照离我的距离排序,最近的排在前面
                    Collections.sort(tempList, new Comparator<BattleAObject>() {
                        @Override
                        public int compare(BattleAObject o1, BattleAObject o2) {
                            return new Float(BattleUtils.getDistance(position, o1.position)).compareTo(BattleUtils.getDistance(position, o2.position));
                        }
                    });

                    for(BattleAObject battleAObject : tempList)
                    {
                        if(!defaultSkill.checkUnitType(battleAObject))
                            continue;

                        if(battleAObject.isDie())
                            continue;

                        if(BattleUtils.isInCircleRange(position, battleAObject.getPosition(), getSoldier().vision))
                        {
                            if(BattleUtils.isInAtkRange(this, battleAObject, defaultSkill.getSkillConfig()))
                            {
                                LogUtils.debug(this + " 旁边有其它兵可以攻击,改变目标去攻击它---------------->" + battleAObject);
                                //告诉客户端攻击了
                                defaultAtk(battleAObject);
                                return true;
                            }
                            //寻路
                            LogUtils.debug(this + " 旁边有其它兵可以看到,向它走去---------------->" + battleAObject);
                            checkRoute(battleAObject);
                            return true;
                        }
                    }
                }
            }
            if(defaultSkill.getDefaultAtkTarget().isDie())
                return false;

            if(BattleUtils.isInAtkRange(this, defaultSkill.getDefaultAtkTarget(), defaultSkill.getSkillConfig()))
            {
                LogUtils.debug(this + " 之前的攻击目标还在攻击范围内,继续攻击 -> " + defaultSkill.getDefaultAtkTarget());
                //告诉客户端攻击了
                defaultSkill.release(defaultSkill.getDefaultAtkTarget());

                checkDefaultAtk();

                checkTypeSkill(ConstantFactory.SKILL_TYPE_ADEFAULT);
                return true;
            }
            else
                return false;

        }
    }

    /**
     * 检查寻路
     */
    @Override
    public void checkFindRoute()
    {
//        LogUtils.debug(" 检测寻路 ->" + this);
        if(goTarget != null || status == E_BattleAObjectStatus.GOING)
            return;

        if(defaultSkill.getDefaultAtkTarget() != null && BattleUtils.isInAtkRange(this, defaultSkill.getDefaultAtkTarget(), defaultSkill.getSkillConfig()))
            return;

        List<BattleAObject> tempList = new CopyOnWriteArrayList<>();
        tempList.addAll(masterController.getAttachment().getTargetBattleTmp().getSoldierList());

        if(tempList.size() > 0)
        {
            //按照离我的距离排序,最近的排在前面
            Collections.sort(tempList, new Comparator<BattleAObject>() {
                @Override
                public int compare(BattleAObject o1, BattleAObject o2) {
                    return new Float(BattleUtils.getDistance(position, o1.position)).compareTo(BattleUtils.getDistance(position, o2.position));
                }
            });


            for(BattleAObject battleAObject : tempList)
            {
                if(!defaultSkill.checkUnitType(battleAObject))
                    continue;

                if(BattleUtils.isInCircleRange(position, battleAObject.getPosition(), getSoldier().vision))
                {
                    if(BattleUtils.isInAtkRange(this, battleAObject, defaultSkill.getSkillConfig()))
                        return;
                    //寻路
                    checkRoute(battleAObject);
                    return;
                }
            }
        }

        if(BattleUtils.isInAtkRange(this, masterController.getAttachment().getTargetBattleTmp().getMasterSoldier(), defaultSkill.getSkillConfig()))
            return;

        checkRoute(masterController.getAttachment().getTargetBattleTmp().getMasterSoldier());
    }

    private void defaultAtk(BattleAObject target)
    {
        setDefaultAtk(target);

        MsgUtils.sendSoldierBattleStart(battleController, this, target);

        defaultSkill.release(target);

        checkDefaultAtk();

        checkTypeSkill(ConstantFactory.SKILL_TYPE_ADEFAULT);
    }


    @Override
    public void checkRoute(BattleAObject target)
    {
        if(moveSpeed.getAtt() <= 0)
        {
            LogUtils.debug("速度为0，不能寻路->" + this);
            return;
        }

        if(!isCanStartMove())
            return;

        if(!isCanGo())
        {
            //被冰冻或者眩晕了，不能行走
            LogUtils.debug("被冰冻或者眩晕了，不能行走 -> this:" + this + " target:" + target);
            return;
        }

//        if(isEffectActioning())
//        {
//            LogUtils.debug("isEffectActioning -> this:" + this + " target:" + target);
//            return;
//        }

        if(masterController.getStatus() != E_PlayerStatus.BATTLE_ING)
        {
            LogUtils.debug("!masterController.isBattling() -> this:" + this + " target:" + target);
            return;
        }

        if(position.isSame(target.getPosition()))
        {
            LogUtils.debug("isSame -> this:" + this + " target:" + target);
            return;
        }

        if(isSameGoTarget(target))
        {
            LogUtils.debug("跟上一次寻路目标相同");
            return;
        }

        if(isDie() || moveSpeed.getAtt() <= 0)
        {
            LogUtils.error("已经死亡或者移动速度为0 -> " + this);
            return;
        }
        LogUtils.debug("当前goTarget:" + goTarget + " -> " + goTargetPosition + " -> " + goTargetOriginalPosMap + " 寻路开始 -> source:" + this + "  target:" + target);

//        GameServer.getInstance().getRouteThread().addRouteObject(new RouteObject(battleController.getId(), uniqueId, target.getTeamNo(), target.getUniqueId()));
        GameServer.getInstance().findRoute(new RouteObject(battleController.getId(), uniqueId, target.getTeamNo(), target.getUniqueId()));
    }




    public void setRouteTarget(BattleAObject target, Position targetPosition)
    {
        goTarget = target;
        goTargetPosition = targetPosition;
        goTargetOriginalPosMap.put(goTarget.getUniqueId(), goTarget.position);
    }

    /**
     * 是否寻路同一个点
     * @param target
     * @return
     */
    @Override
    public boolean isSameGoPosition(Position target)
    {
        return super.isSameGoPosition(target) && routeList != null && routeList.size() > 0;
    }


    /**
     * 对敌人造成的伤害增加
     * @param value
     */
    @Override
    public void addDamage(long value)
    {
        this.damage += value;

        if(summonMaster != null && summonMaster.getSpriteTemp() != null)
        {
            summonMaster.getSpriteTemp().setToEnemyDamage(damage);
        }
        else if(spriteTemp != null)
        {
            spriteTemp.setToEnemyDamage(damage);
        }
    }




    public BattleAObject getSummonMaster() {
        return summonMaster;
    }

    public SoldierConfig getSoldier() {
        return (SoldierConfig) sprite;
    }


    public List<Position> getRouteList() {
        return routeList;
    }

    public void setRouteList(List<Position> routeList) {
        this.routeList = routeList;
    }

    public int getCurRouteIndex() {
        return curRouteIndex;
    }

    public void setCurRouteIndex(int curRouteIndex) {
        this.curRouteIndex = curRouteIndex;
    }




}
